package cn.com.open.itembank.service.impl;

import cn.com.open.itembank.common.CommonFunction;
import cn.com.open.itembank.common.CustomXWPFDocument;
import cn.com.open.itembank.common.Function;
import cn.com.open.itembank.common.GlobalConst;
import cn.com.open.itembank.common.enums.AnswerType;
import cn.com.open.itembank.common.enums.ItemType;
import cn.com.open.itembank.common.enums.PaperImportType;
import cn.com.open.itembank.dto.*;
import cn.com.open.itembank.entity.CourseItemBank;
import cn.com.open.itembank.entity.TestPaperContent;
import cn.com.open.itembank.exception.PoiException;
import cn.com.open.itembank.mapper.PaperReadMapper;
import cn.com.open.itembank.service.ItemBankRemoteService;
import cn.com.open.itembank.service.PaperExportService;
import cn.com.open.itembank.service.PaperService;
import cn.com.open.itembank.utils.*;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 试卷导出
 */
@Service
public class PaperExportServiceImpl implements PaperExportService {

    private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(PaperExportServiceImpl.class);

    @Value("${itembank.tempFileBasePath}")
    public String tempFilePath;

    @Autowired
    private PaperService paperService;

    @Autowired
    private PaperReadMapper mapper;

    @Autowired
    private ItemBankRemoteService itemBankService;


    private static String exportString = "export";
    private static int fontSize = 11;
    private static String fontFamily = "宋体";
    private static String answer = "[正确答案]：";

    //region 试卷导出

    /**
     * 试卷导出
     *
     * @param appKey      appKey
     * @param itemBankId  题库ID
     * @param testPaperId 试卷编号
     * @param importType  是否含答案：0，试卷；1，试卷和答案；2，试卷含答案
     * @return the return model
     * @throws Exception the exception
     */
    @Override
    public ReturnModel paperExportWord(String itemBankId, String testPaperId, PaperImportType importType, String appKey)
            throws PoiException, ZipException {

        //返回类
        ReturnModel returnModel = new ReturnModel();

        String zName = getZipFilePath();
        ZipFile newZip = new ZipFile(zName);
        String[] paperIdList = testPaperId.split(",");
        for (int i = 0; i < paperIdList.length; i++) {
            //调用接口(验证)
            ReturnModel model = paperService.getTestPaper(itemBankId, paperIdList[i], AnswerType.ALL, false);

            //通过验证得到试卷模型
            TestPaperModel testPaperModel = (TestPaperModel) model.getData();

            //组成导出压缩文件
            String name = makeZipFile(testPaperModel, importType);

            ZipParameters parameters = new ZipParameters();
            //设置参数
            parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
            parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
            // 如果仅为一张试卷导出
            if (paperIdList.length == 1) {
                returnModel.setData(name);
                returnModel.setCode(GlobalConst.SUCCESS);
                return returnModel;
            }
            //添加
            newZip.addFile(new File(name), parameters);
        }
        String zipFileName = zName.replaceFirst("/", "");
        //成功返回
        returnModel.setData(zipFileName);
        returnModel.setMessage("导出成功");
        returnModel.setCode(GlobalConst.SUCCESS);
        return returnModel;
    }

    //endregion

    //region 写入文档

    //region 组成导出压缩文件

    /**
     * 组成导出压缩文件.
     *
     * @param paperExportModel 试卷导出模型
     * @param importType       是否含答案：0，试卷；1，试卷和答案；2，试卷含答案
     * @return the string
     * @throws Exception the exception
     */
    private String makeZipFile(TestPaperModel paperExportModel, PaperImportType importType) throws PoiException, ZipException {

        //获取zip包的名字
        String zipFileName = getZipFilePath();
        //获取zip包的路径名
        ZipFile zipFile = new ZipFile(zipFileName);

        //获取word的路径名
        String fileName = getWordFilePath();

        //获取答案word的路径名
        String answerFileName = getAnswerWordFilePath();

        //删除给定文件夹下多于一天的历史记录
        FileUtils.deleteOldFiles(new File(fileName));
        //写入word
        printWord(paperExportModel, importType, fileName, zipFile);

        //把word添加到zip
        ArrayList filesToAdd = new ArrayList();
        filesToAdd.add(new File(fileName));

        if (importType.getIndex() == 1) {
            printAnswerWord(paperExportModel, answerFileName);
            filesToAdd.add(new File(answerFileName));
        }
        ZipParameters parameters = new ZipParameters();
        //设置参数
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
        //添加
        zipFile.addFiles(filesToAdd, parameters);
        return zipFileName;
    }
    //endregion

    //region 获取答案

    /**
     * 获取答案.
     * 试题和答案(答案需要重新写到另一个word上)
     *
     * @param testPaperModel 试卷导出模型
     * @param answerFileName 答案路径名
     * @throws Exception the exception
     */
    private void printAnswerWord(TestPaperModel testPaperModel, String answerFileName)
            throws PoiException {

        try (CustomXWPFDocument document = new CustomXWPFDocument()) {
            //文档标题
            XWPFParagraph doc = document.createParagraph();
            //文字对齐方式
            doc.setAlignment(ParagraphAlignment.CENTER);
            doc.setVerticalAlignment(TextAlignment.TOP);
            XWPFRun paperRun = doc.createRun();
            paperRun.setText(testPaperModel.getModel().getP2());
            paperRun.setFontSize(18);
            paperRun.setBold(true);

            //"[参考答案]"四个字占一个段落
            XWPFParagraph answerTrue = document.createParagraph();
            answerTrue.setAlignment(ParagraphAlignment.CENTER);
            answerTrue.setVerticalAlignment(TextAlignment.TOP);
            XWPFRun ckDa = answerTrue.createRun();
            ckDa.setText("参考答案");
            ckDa.setBold(true);
            ckDa.setFontSize(14);

            //得到所有试题
            List<Object> itemsList = testPaperModel.getItems();

            int k = 1;
            int x = 1;
            for (PaperPart paperPart : testPaperModel.getParts()) {
                List<PaperSection> sectionsList = paperPart.getSections();
                for (int i = 0; i < sectionsList.size(); i++) {
                    //大题题型
                    XWPFParagraph sectionName = document.createParagraph();
                    XWPFRun sectionNameRun = sectionName.createRun();
                    sectionName.setAlignment(ParagraphAlignment.LEFT);
                    sectionName.setVerticalAlignment(TextAlignment.TOP);
                    sectionNameRun.setBold(true);
                    sectionNameRun.setFontSize(14);
                    sectionNameRun.setText(getMap(k) + "、" + sectionsList.get(i).getTitle());
                    for (int j = 0; j < itemsList.size(); j++) {
                        QuestionModel questionModel = (QuestionModel) itemsList.get(j);
                        if (questionModel.getI30().equals(sectionsList.get(i).getIdentifier())) {
                            XWPFParagraph an = document.createParagraph();
                            an.setAlignment(ParagraphAlignment.LEFT);
                            an.setVerticalAlignment(TextAlignment.TOP);
                            XWPFRun run = an.createRun();
                            //单选，多选，判断
                            if (questionModel.getI3() == ItemType.SINGLECHOICE.getIndex() ||
                                    questionModel.getI3() == ItemType.MULTIPLECHOICE.getIndex() ||
                                    questionModel.getI3() == ItemType.JUDGEMENT.getIndex()) {
                                run.setText(x + "." + CommonFunction.getAnswerData(questionModel.getI7()));
                                x++;
                            }
                            //填空，问答
                            if (questionModel.getI3() == ItemType.TEXTENTRY.getIndex() ||
                                    questionModel.getI3() == ItemType.EXTENDEDTEXT.getIndex()) {
                                run.setText(x + "." + questionModel.getI6());
                                x++;
                            }
                            //完型填空，阅读理解
                            if (questionModel.getI3() == ItemType.CLOZE.getIndex() ||
                                    questionModel.getI3() == ItemType.READINGCOMPREHENSION.getIndex()) {
                                for (QuestionModel sub : questionModel.getSub()) {
                                    run.setText(x + "." + CommonFunction.getAnswerData(sub.getI7()) + ",  ");
                                    x++;
                                }
                            }
                            //匹配题
                            if (questionModel.getI3() == ItemType.MATCH.getIndex()) {
                                for (QuestionModel sub : questionModel.getSub()) {
                                    run.setText(x + "." + CommonFunction.getAnswerData(sub.getI7()) + ",  ");
                                    run.addBreak();
                                    x++;
                                }
                            }
                            //组合题
                            if (questionModel.getI3() == ItemType.COMPOSITE.getIndex()) {
                                for (QuestionModel sub : questionModel.getSub()) {
                                    if (sub.getI3() == ItemType.EXTENDEDTEXT.getIndex() ||
                                            sub.getI3() == ItemType.TEXTENTRY.getIndex()) {
                                        run.setText(x + "." + sub.getI6());
                                    } else {
                                        run.setText(x + "." + CommonFunction.getAnswerData(sub.getI7()) + ",  ");
                                    }
                                    run.addBreak();
                                    x++;
                                }
                            }
                            run.addBreak();
                        }
                    }
                    k++;
                }
            }
            //输出流
            FileOutputStream out = new FileOutputStream(answerFileName);
            //写入word中
            document.write(out);
            //关流
            out.close();
        } catch (Exception e) {
            throw new PoiException(e.getMessage());
        }
    }
    //endregion

    //region 输出word(试卷标题)

    /**
     * 输出word.
     *
     * @param testPaperModel 试卷导出模型
     * @param fileName       文件包路径名
     * @param zipFile        zip 文件包
     * @param importType     含答案类型：0，试卷；1，试卷和答案；2，试卷含答案
     * @throws Exception the exception
     */
    private void printWord(TestPaperModel testPaperModel, PaperImportType importType, String fileName, ZipFile zipFile)
            throws PoiException {

        try (CustomXWPFDocument doc = new CustomXWPFDocument()) {
            //设置word文档的格式
            XWPFParagraph paraPaper = doc.createParagraph();
            //创建段落1(写试卷标题)
            XWPFRun runPaper = paraPaper.createRun();
            //文字对齐方式
            paraPaper.setAlignment(ParagraphAlignment.CENTER);
            paraPaper.setVerticalAlignment(TextAlignment.TOP);

            List<Object> itemsList = testPaperModel.getItems();
            List<PaperPart> partsList = testPaperModel.getParts();

            runPaper.setText(testPaperModel.getModel().getP2() + "(共" + testPaperModel.getModel().getP5() + "分)");
            //word文档格式（加粗、字体、换行）
            runPaper.setBold(true);
            runPaper.setFontSize(18);

            int j = 1;
            for (PaperPart paperPart : partsList) {
                List<PaperSection> sectionsList = paperPart.getSections();
                int a = 1;

                for (int i = 0; i < sectionsList.size(); i++) {
                    //设置word文档的格式
                    XWPFParagraph paraSection = doc.createParagraph();
                    if (i != 0)
                        paraSection.setPageBreak(true);
                    //创建段落2(写大题标识)
                    XWPFRun runSection = paraSection.createRun();

                    List<PaperItem> items = sectionsList.get(i).getItems();
                    //大题总分+大题标题
                    runSection.setText(getMap(a) + "、" + sectionsList.get(i).getTitle() + "(共" + items.size() + "题，共" + sectionsList.get(i).getScore() + "分)");
                    a++;
                    //word文档格式(加粗、字体、换行)
                    runSection.setBold(true);
                    runSection.setFontSize(14);

                    for (PaperItem paperItem : items) {
                        for (Object model : itemsList) {
                            QuestionModel questionModel = (QuestionModel) model;
                            //找到对应的试题
                            if (paperItem.getItemId().equalsIgnoreCase(questionModel.getI1())) {
                                //处理试题
                                processQuestion(doc, questionModel, importType, zipFile, j);
                                //处理题号
                                j += questionModel.getSub() != null && !questionModel.getSub().isEmpty() ? questionModel.getSub().size() : 1;
                            }
                        }
                    }
                }
            }
            //输出流
            FileOutputStream out = new FileOutputStream(fileName);
            //写入word中
            doc.write(out);
            //关流
            out.close();
        } catch (Exception e) {
            throw new PoiException(e.getMessage());
        }
    }

    //endregion

    //region 字符串转换（1转一，2转二）

    /**
     * 字符串转换(匹配大题的一、二、三等等)
     *
     * @param a
     * @return string
     */
    private String getMap(int a) {

        String[] arr = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一"};

        for (int i = 0; i < 100; i++) {
            if (a == i) {
                return arr[i - 1];
            }
        }
        return null;
    }
    //endregion

    //region 组织word(试题)

    /**
     * 组织word
     *
     * @param questionModel 试题模型
     * @param doc           文档
     */
    private void processQuestion(CustomXWPFDocument doc, QuestionModel questionModel, PaperImportType importType, ZipFile zipFile, int j) throws ZipException, IOException {
        //小题的单独处理
        paperExportWordModelFromFilterModel(questionModel, doc, zipFile, j, importType);

        //含答案处理
        writerAnswer(questionModel, doc, importType);
    }

    /**
     * 处理答案
     *
     * @param questionModel 试题模型
     * @param doc           doc文档
     * @param importType    导出方式
     */
    private void writerAnswer(QuestionModel questionModel, CustomXWPFDocument doc, PaperImportType importType) {
        //  仅支持7种基本题型
        XWPFParagraph para = doc.createParagraph();
        XWPFRun run = para.createRun();
        if (importType == PaperImportType.PAPER_INCLUDE_ANSWER) {
            if (questionModel.getI3() == ItemType.SINGLECHOICE.getIndex()
                    || questionModel.getI3() == ItemType.MULTIPLECHOICE.getIndex()
                    || questionModel.getI3() == ItemType.JUDGEMENT.getIndex()) {
                // "[正确答案]：A"

                run.setText(answer + CommonFunction.getAnswerData(questionModel.getI7()));
            } else if (questionModel.getI3() == ItemType.EXTENDEDTEXT.getIndex() ||
                    questionModel.getI3() == ItemType.TEXTENTRY.getIndex()) {
                // "[正确答案]：abc, 123"

                StringBuilder answerStr = new StringBuilder();
                for (Integer i = 0; i < questionModel.getI6().size(); i++) {
                    if (i != 0)
                        answerStr.append(", ");
                    answerStr.append(questionModel.getI6().get(i).split("##")[0]);
                }
                run.setText(answer + answerStr);
            }
//            if(questionModel.getI3() == ItemType.COMPOSITE.getIndex()){
//                for(QuestionModel sub :questionModel.getSub()){
//                    writerAnswer(sub, doc, importType);
//                }
//
//            }
        }

        //设置字体类型
        run.setFontFamily(fontFamily);
        //设置字体大小
        run.setFontSize(fontSize);
    }


    //endregion

    //region处理单个试题

    /**
     * 处理大题题型
     *
     * @return return model
     * @throws IOException the io exception
     */
    private void paperExportWordModelFromFilterModel(QuestionModel questionModel, CustomXWPFDocument doc, ZipFile zipFile, int idx, PaperImportType importType) throws ZipException, IOException {
        int newIdx = idx;
        //匹配题干
        // 排序题未测试
        if ((questionModel.getI3() == ItemType.SINGLECHOICE.getIndex()) || (questionModel.getI3() == ItemType.MULTIPLECHOICE.getIndex()) ||
                (questionModel.getI3() == ItemType.JUDGEMENT.getIndex()) || (questionModel.getI3() == ItemType.ORDER.getIndex())) {
            // 单选，多选，判断，排序
            // 处理富文本文件(处理音频，图片，表格）
            processAttachments(newIdx + ". " + questionModel.getI2(), doc, zipFile);
            // 输出选项(A,B,C,D)
            for (Integer i = 0; i < questionModel.getI6().size(); i++) {
                processAttachments(Function.byteAsciiToChar(65 + i) + ". " + questionModel.getI6().get(i), doc, zipFile);
            }
        } else if (questionModel.getI3() == ItemType.TEXTENTRY.getIndex()) {
            //填空题
            processAttachments(newIdx + "." + questionModel.getI2().replace("##", "_____"), doc, zipFile);
        } else if (questionModel.getI3() == ItemType.EXTENDEDTEXT.getIndex()) {
            //问答题
            processAttachments(newIdx + "." + questionModel.getI2(), doc, zipFile);
            doc.createParagraph();
            doc.createParagraph();
            doc.createParagraph();
            doc.createParagraph();
            doc.createParagraph();
        } else if (questionModel.getI3() == ItemType.MATCH.getIndex()) {
            // 匹配题
            List<QuestionModel> subList = questionModel.getSub();
            for (int i = 0; i < subList.size(); i++) {
                processAttachments(newIdx + "." + subList.get(i).getI2(), doc, zipFile);
                if (importType == PaperImportType.PAPER_INCLUDE_ANSWER) {
                    XWPFParagraph paragraph = doc.createParagraph();
                    paragraph.createRun().setText(answer + CommonFunction.getAnswerData(subList.get(i).getI7()));
                }
                newIdx++;
            }
            doc.createParagraph();
            for (int i = 0; i < questionModel.getI6().size(); i++) {
                processAttachments(Function.byteAsciiToChar(65 + i) + "." + questionModel.getI6().get(i), doc, zipFile);
            }
        } else if (questionModel.getI3() == ItemType.READINGCOMPREHENSION.getIndex()) {
            // 组合题未测试
            //组合题，阅读理解
            processAttachments(questionModel.getI2(), doc, zipFile);

            if (!questionModel.getSub().isEmpty()) {
                for (QuestionModel sub : questionModel.getSub()) {
                    processAttachments(newIdx + "." + sub.getI2(), doc, zipFile);
                    newIdx++;
                    //输出选项
                    for (Integer i = 0; i < sub.getI6().size(); i++) {
                        processAttachments(Function.byteAsciiToChar(65 + i) + "." + sub.getI6().get(i), doc, zipFile);
                    }
                    if (importType == PaperImportType.PAPER_INCLUDE_ANSWER) {
                        XWPFParagraph paragraph = doc.createParagraph();
                        paragraph.createRun().setText(answer + CommonFunction.getAnswerData(sub.getI7()));
                    }
                }
            }
        } else if (questionModel.getI3() == ItemType.UPLOAD.getIndex()) {
            // 上传题未测试
            //上传题
            processAttachments("  " + questionModel.getI2(), doc, zipFile);
        } else if ((questionModel.getI3() == ItemType.CLOZE.getIndex())) {
            // 完型填空
            // 设置首行缩进
            // 替换##为__
            String[] titleList = questionModel.getI2().split("##");
            StringBuilder titleStr = new StringBuilder();
            for (int j = 0; j < titleList.length; j++) {
                if (j != 0) {
                    titleStr.append(" __" + (idx + j - 1) + "__ ");
                }
                titleStr.append(titleList[j]);
            }
            processAttachments(titleStr.toString(), doc, zipFile);
            //完形填空
            if (!questionModel.getSub().isEmpty()) {
                for (QuestionModel sub : questionModel.getSub()) {
                    processAttachments(newIdx + ".", doc, zipFile);
                    //输出选项
                    for (Integer i = 0; i < sub.getI6().size(); i++) {
                        processAttachments(Function.byteAsciiToChar(65 + i) + "." + sub.getI6().get(i), doc, zipFile);
                    }
                    if (importType == PaperImportType.PAPER_INCLUDE_ANSWER) {
                        XWPFParagraph paragraph = doc.createParagraph();
                        paragraph.createRun().setText(answer + CommonFunction.getAnswerData(sub.getI7()));
                    }
                    newIdx++;
                }
            }
        }
        //组合题
        if (questionModel.getI3() == ItemType.COMPOSITE.getIndex()) {
            processAttachments(questionModel.getI2(), doc, zipFile);
            for (QuestionModel sub : questionModel.getSub()) {
                paperExportWordModelFromFilterModel(sub, doc, zipFile, newIdx, importType);
//                if (importType == PaperImportType.PAPER_INCLUDE_ANSWER &&
//                        sub.getI3() != ItemType.EXTENDEDTEXT.getIndex() &&
//                        sub.getI3() != ItemType.TEXTENTRY.getIndex()) {
//                    XWPFParagraph paragraph = doc.createParagraph();
//                    paragraph.createRun().setText(answer + CommonFunction.getAnswerData(sub.getI7()));
//                }
                if (importType == PaperImportType.PAPER_INCLUDE_ANSWER) {
                    writerAnswer(sub, doc, importType);
                }

                newIdx++;
            }
        }
    }
    //endregion

    //region 处理附件

    /**
     * 处理附件.
     *
     * @param content the content
     * @param doc     the CustomXWPFDocument
     * @param zipFile the zip file
     */
    private void processAttachments(String content, CustomXWPFDocument doc, ZipFile zipFile) throws ZipException, IOException {
        //创建一个段落
        XWPFParagraph paragraph = doc.createParagraph();

        //得到所有内容列表
        List<String> contentList = Function.splitByPattern(content);
        for (String item : contentList) {
            XWPFRun run = paragraph.createRun();
            if (item.contains("<img")) {
                writeImage(Function.findPath(item), run);
            } else if (item.contains("<media") || item.contains("<video")) {
                writeMedia(Function.findPath(item), run, zipFile);
            } else if (item.contains("<table")) {
                run = paragraph.createRun();
                List<List<List<String>>> lists = CommonFunction.getTableContent(item);
                for (int j = 0; j < lists.size(); j++) {
                    writeTable(run, lists.get(j));
                }
                // 添加Table后另起一行
                paragraph = doc.createParagraph();
            } else {
                writeNormalContent(item, run);
            }
        }
    }
    //endregion

    //region 输出附件内容

    /**
     * 输出附件内容.
     *
     * @param filePath the content
     * @param run      the XWPFRun
     */
    private void writeImage(String filePath, XWPFRun run) throws IOException {
        //下载远端图片文件，返回文件路径
        String imgFile = downloadImgFileAndGetFullPath(filePath);

        //将图片文件输出到文档
        createPic(run, imgFile);
    }

    /**
     * 输出附件内容.
     *
     * @param filePath the content
     * @param run      the XWPFRun
     * @param zipFile  the zip file
     */
    private void writeMedia(String filePath, XWPFRun run, ZipFile zipFile) throws ZipException, IOException {
        //把音频文件放到网络路径上，并非本地路径
        writeNormalContent(String.format(" [音频文件：%s] ", downloadAudioFileAndGetFileName(filePath, zipFile)), run);
    }
    //endregion

    //region 将图片文件输出到文档

    /**
     * 将图片文件输出到文档.
     *
     * @param run     the XWPFRun
     * @param imgFile the image file
     * @throws InvalidFormatException the invalid format exception
     */
    private void createPic(XWPFRun run, String imgFile) throws IOException {
        CustomXWPFDocument doc = (CustomXWPFDocument) run.getParagraph().getDocument();

        try {
            byte[] imageByte = FileUtils.image2byte(imgFile);
            int formatType = XWPFDocument.PICTURE_TYPE_PNG;

            if (imgFile.toLowerCase().lastIndexOf(".png") < 0) {
                formatType = XWPFDocument.PICTURE_TYPE_JPEG;
            }

            doc.addPictureData(imageByte, formatType);
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }

        File picture = new File(imgFile);
        BufferedImage sourceImg = ImageIO.read(new FileInputStream(picture));

        int newWidth = 300;
        int newHeight = 0;
        if (sourceImg.getWidth() < newWidth) {
            newWidth = sourceImg.getWidth();
            newHeight = sourceImg.getHeight();
        } else {
            newHeight = sourceImg.getHeight() / (sourceImg.getWidth() / newWidth);
        }

        doc.createPicture(run.getParagraph(), doc.getAllPictures().size() - 1, newWidth, newHeight, "");
    }
    //endregion

    //region 下载远端图片文件，返回文件路径

    /**
     * 下载远端图片文件，返回文件路径.
     *
     * @param urlPath 图片文件url
     * @return 图片文件路径 string
     * @throws Exception the exception
     */
    public String downloadImgFileAndGetFullPath(String urlPath) throws IOException {
        //文件名称
        String fileName = CommonFunction.getImgFileName(urlPath);
        //本地保存路径
        String filePath = CommonFunction.getFileFullPath(exportString, fileName);
        //下载并保存文件
        FileUtils.writeUrlFileToLocal(urlPath, filePath);
        //返回图片文件路径
        return filePath;
    }

    //endregion

    //region 下载远端音频文件并且保存到zip文件，返回音频文件名

    /**
     * 下载远端音频文件并且保存到zip文件，返回音频文件名.
     *
     * @param urlPath 音频文件url
     * @param zipFile zip文件
     * @return 音频文件名 string
     * @throws Exception the exception
     */
    public String downloadAudioFileAndGetFileName(String urlPath, ZipFile zipFile) throws ZipException, IOException {
        //文件名称
        String fileName = String.format("%s.mp3", DateUtil.getCurrentTimeToLongString());
        //本地保存路径
        String filePath = CommonFunction.getFileFullPath(exportString, fileName);
        //下载并保存文件
        FileUtils.writeUrlFileToLocal(urlPath, filePath);
        //写入zip
        addFileToZip(filePath, zipFile);

        return fileName;
    }
    //endregion

    //region 将文件添加入Zip

    /**
     * 将文件添加入Zip.
     *
     * @param file    文件有效的绝对路径
     * @param zipFile the zip file
     * @throws ZipException the zip exception
     */
    private void addFileToZip(String file, ZipFile zipFile) throws ZipException {
        ArrayList filesToAdd = new ArrayList();
        filesToAdd.add(new File(file));
        //
        ZipParameters parameters = new ZipParameters();
        //设置参数
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);

        parameters.setRootFolderInZip("audios/");

        zipFile.addFiles(filesToAdd, parameters);
    }
    //endregion

    //region 输出普通内容信息

    /**
     * 输出普通内容信息.
     *
     * @param content the content
     * @param run     the XWPFRun
     */
    private void writeNormalContent(String content, XWPFRun run) {
        run.setText(CommonFunction.processeHTML(content));
        //字体类型
        run.setFontFamily(fontFamily);
        //字体大小
        run.setFontSize(fontSize);
    }
    //endregion

    //region 根据表格内容输出word表格

    /**
     * 根据表格内容输出word表格.
     *
     * @param run          the XWPFRun
     * @param tableContent the table content
     */
    private void writeTable(XWPFRun run, List<List<String>> tableContent) {
        if (tableContent == null || tableContent.isEmpty() || tableContent.get(0).isEmpty()) {
            return;
        }

        CustomXWPFDocument doc = (CustomXWPFDocument) run.getParagraph().getDocument();
        XWPFTable xwpfTable = doc.createTable(tableContent.size(), tableContent.get(0).size());

        List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();

        //创建
        XWPFTableRow row;
        List<XWPFTableCell> cells;
        XWPFTableCell cell;

        int rowSize = xwpfTableRows.size();
        int cellSize;

        for (int i = 0; i < rowSize; i++) {
            row = xwpfTableRows.get(i);
            cells = row.getTableCells();
            cellSize = cells.size();
            for (int j = 0; j < cellSize; j++) {
                cell = cells.get(j);
                cell.setText(tableContent.get(i).get(j));
            }
        }
    }
    //endregion

    //region 获得导出的zip文件名称路径

    /**
     * 获得导出的zip文件名称路径.
     *
     * @return the file
     */
    private String getZipFilePath() {

        //zip名字
        String fileName = String.format("%s.zip", DateUtil.getCurrentTimeToLongString());
        String bathPath = PathUtil.getBathPath(tempFilePath);

        return String.format("%s%s", bathPath, fileName);
//
//        //导出文件名称
//        String fileName = String.format("试题包-%s.zip", DateUtil.getCurrentTimeToLongString());
//
//        return CommonFunction.getFileFullPath("package", fileName);
    }
    //endregion

    //region 获得导出的文件名称路径

    /**
     * 获得导出的word文件名称路径.
     *
     * @return the file
     */
    private String getWordFilePath() {

        //导出文件名称
        String fileName = String.format("%s.docx", DateUtil.getCurrentTimeToLongString());
        String bathPath = PathUtil.getBathPath(tempFilePath);

        return String.format("%s%s", bathPath, fileName);


        //return CommonFunction.getFileFullPath(exportString, fileName);
    }

    //endregion

    //region 获得答案导出的文件名称路径

    /**
     * 获得导出的答案word文件名称路径.
     *
     * @return the file
     */
    private String getAnswerWordFilePath() {
        //导出文件名称
        String answerFileName = String.format("[答案]-%s.docx", DateUtil.getCurrentTimeToLongString());

        String bathPath = PathUtil.getBathPath(tempFilePath);

        return String.format("%s%s", bathPath, answerFileName);


        //return CommonFunction.getFileFullPath(exportString, answerFileName);
    }

    //endregion
    //endregion


    //region 根据题库id获取试卷xml结构

    /**
     * 根据题库id获取试卷xml结构
     *
     * @param itemBankId 题库id
     * @param appKey     appKey
     * @return ReturnModel
     */
    @Override
    public ReturnModel exportPaperXML(String itemBankId, String appKey) throws ZipException, IOException {
        //基础检验
        ReturnModel model = baseCheck(itemBankId, appKey);
        if (model.getCode() != GlobalConst.SUCCESS) {
            return model;
        }

        //设置参数
        ZipParameters parameters = new ZipParameters();
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
        //设置压缩文件加密
        parameters.setEncryptFiles(true);
        //设置加密方法
        parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
        //设置aes加密强度
        parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
        //设置密码
        parameters.setPassword((itemBankId.substring(0, 8)).toUpperCase());

        //获取zip包的名字
        String zipFileName = getZipFilePathXML(itemBankId);
        //获取zip包的路径名
        ZipFile zipFilePath = new ZipFile(zipFileName);

        //第一层文件夹路径
        String itemBankNamePath = PathUtil.getBathPath(tempFilePath) + itemBankId;

        //获取第一层文件夹名称
        File itemBankName = new File(itemBankNamePath);
        if (itemBankName.exists()) {
            model.setCode(GlobalConst.SUCCESS);
            model.setData(zipFileName);
            model.setMessage("此文件已存在，请下载");
            return model;
        }
        //创建文件夹
        itemBankName.mkdirs();
        //获取第二层文件夹名称
        File AssessmentItems = new File(PathUtil.getBathPath(tempFilePath) + itemBankId + "/AssessmentItems");
        AssessmentItems.mkdirs();

        String questionContent = "";
        String path = "";
        String currentTimeName = "";
        //通过题库id获取题库下的paperID
        List<String> testPaperIdList = mapper.getTestPaperIDById(itemBankId);
        for (String testPaperId : testPaperIdList) {

            TestPaperContent xml = mapper.getTestPaperXML(testPaperId);
            String paperContentXml = xml.getContentXml();
            File itemBankNameFile = new File(itemBankName, "AST_" + testPaperId + ".xml");
            try (FileOutputStream fou = new FileOutputStream(itemBankNameFile)) {
                fou.write(paperContentXml.getBytes());
            }
            if (paperContentXml.contains("href")) {
                List<String> strings = splitByPattern(paperContentXml);
                for (int i = 0; i < strings.size(); i++) {

                    if (strings.get(i).contains("href")) {
                        StringBuffer newQuestionContent = new StringBuffer();
                        int hrefIndex = strings.get(i).indexOf("ASI_");
                        int xMlIndex = strings.get(i).indexOf(".xml");
                        String SAIString = strings.get(i).substring(hrefIndex, xMlIndex);

                        String questionId = SAIString.replace("ASI_", "");
                        String questionContentXML = mapper.getQuestionContent(questionId);
                        String imgName = questionId.replace("-", "");
                        File AssessmentItemsFile = new File(AssessmentItems, SAIString + ".xml");
                        //含图片处理
                        if (questionContentXML.contains("img")) {
                            //获取第三层文件夹名称
                            File picture = new File(PathUtil.getBathPath(tempFilePath) + itemBankId + "/AssessmentItems/" + questionId);
                            picture.mkdirs();

                            List<String> imgS = splitByPattern(CommonFunction.formatToHtml(questionContentXML));
                            for (int j = 0; j < imgS.size(); j++) {
                                if (!imgS.get(j).contains("img")) {
                                    newQuestionContent.append(imgS.get(j));
                                }
                                if (imgS.get(j).contains("img")) {
                                    currentTimeName = imgName + "_" + j;
                                    path = Function.findPath(imgS.get(j));
                                    FileUtils.writeUrlFileToLocal(path, picture.toString() + "/" + currentTimeName + path.substring(path.lastIndexOf(".")));
                                    questionContent = imgS.get(j).replace(path, questionId + "/" + currentTimeName + path.substring(path.lastIndexOf(".")));
                                    newQuestionContent.append(questionContent);
                                }
                            }
                            String s = newQuestionContent.toString();
                            try (FileOutputStream fow = new FileOutputStream(AssessmentItemsFile)) {
                                fow.write(s.getBytes());
                            }
                        } else {//不含图片处理
                            try (FileOutputStream fow = new FileOutputStream(AssessmentItemsFile)) {
                                fow.write(questionContentXML.getBytes());
                            }
                        }
                    }
                }
            }
        }
        zipFilePath.addFolder(itemBankName, parameters);
        model.setCode(GlobalConst.SUCCESS);
        model.setMessage("此文件已存在，请下载");
        model.setData(zipFileName);
        return model;
    }

    //endregion

    //region 基本验证

    /**
     * 基本验证
     *
     * @param itemBankId 题库id
     * @param appKey     appKey
     * @return ReturnModel
     */
    private ReturnModel baseCheck(String itemBankId, String appKey) {
        ReturnModel model = new ReturnModel();

        if (StringUtil.isEmpty(itemBankId) || (!UUIDUtil.isUUID(itemBankId))) {
            model.setCode(GlobalConst.ID_NOT_EXIST);
            model.setMessage("题库ID不合法");
            return model;
        }

        CourseItemBank courseItemBank = mapper.CourseItemBank(itemBankId);
        if (courseItemBank == null) {
            model.setCode(GlobalConst.DATA_FORMAT_ERROR);
            model.setMessage("题库不存在");
            return model;
        }

        //确认除非非限定appId否则只能修改appId
        if (StringUtils.isEmpty(appKey) || !itemBankService.hasPermission(itemBankId, appKey)) {
            model.setCode(GlobalConst.NO_PERMISSION);
            model.setMessage("无权限操作");
            return model;
        }
        model.setCode(GlobalConst.SUCCESS);
        return model;
    }
    //endregion

    //region  组成压缩文件

    /**
     * 获取zip名字
     *
     * @return
     */
    private String getZipFilePathXML(String name) {
        //zip名字
        String fileName = String.format("%s.zip", name);
        String bathPath = PathUtil.getBathPath(tempFilePath);

        return String.format("%s%s", bathPath, fileName);


        //String fileName = String.format("%s.zip", name);
        //return CommonFunction.getFileFullPath("xml", fileName);
    }
    //endregion

    /**
     * 正则（过滤xml标签）
     *
     * @param str
     * @return
     */
    public List<String> splitByPattern(String str) {
        List<String> result = new ArrayList<>();
        int lastIndex = 0;
        Pattern pattern = Pattern.compile("(<assessmentItemRef[^>]*?>[\\s\\S]*?<\\/assessmentItemRef>|<img*?[\\s\\S]*?\\/>|<img*?[\\s\\S]*?>)");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            if (!StringUtil.isEmpty(str.substring(lastIndex, matcher.start()))) {
                result.add(str.substring(lastIndex, matcher.start()));
            }
            result.add(matcher.group());
            lastIndex = matcher.end();
        }
        if (lastIndex < str.length())
            result.add(str.substring(lastIndex));
        else if (lastIndex == 0)
            result.add(str);

        return result;
    }
}
